﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Audio;
namespace Project1
{
    public class Bat
    {
        #region Member Variable
        private TurretGame game;
        private Model bat;
        private int leftWing1;
        private int leftWing2;
        private int rightWing1;
        private int rightWing2;
        private int score = 0;
        private LinkedList<BatObj> bats = new LinkedList<BatObj>();
        private Random random = new Random();
        private Vector3 RandomVector(float min, float max)
        {
            return new Vector3((float)(min + (random.NextDouble() * (max - min))),
                (float)(min + (random.NextDouble() * (max - min))),
                (float)(min + (random.NextDouble() * (max - min))));
        }
        float wingAngle = 0;
        bool down = true;
        bool up = false;
        float angleRate = 5f;
        #endregion

        #region Construction
        public Bat(TurretGame game)
        {
            this.game = game;

        }
        #endregion

        #region BatObj
        public class BatObj
        {
            public Vector3 position;
            public float velocity;
            public float azimuth = 0;
            public float elevation = 0;
            public float size;
            public float health;
        }
        #endregion

        #region Property 
        public int batLeft { get { return bats.Count; } }
        public int Score { get { return score; } }
        #endregion 

        #region Load
        public void LoadContent(ContentManager content)
        {
            bat = content.Load<Model>("Bat-rigid");
            leftWing1 = bat.Bones.IndexOf(bat.Bones["LeftWing1"]);
            leftWing2 = bat.Bones.IndexOf(bat.Bones["LeftWing2"]);
            rightWing1 = bat.Bones.IndexOf(bat.Bones["RightWing1"]);
            rightWing2 = bat.Bones.IndexOf(bat.Bones["RightWing2"]);
            startGame();

        }
        #endregion

        #region Update
        public void Update(GameTime gameTime)
        {
            // Update the change of wings
            float delta = (float)gameTime.ElapsedGameTime.TotalSeconds;
            if (down && wingAngle < 2.0f)
            {
                wingAngle += angleRate * delta;
            }
            if (wingAngle >= 2.0f)
            {
                down = false;
                up = true;
            }

            if (up && wingAngle > -1f)
            {
                wingAngle -= angleRate * delta;
            }
            if (wingAngle <= -1f)
            {
                down = true;
                up = false;
            }

            foreach (BatObj batS in bats)
            {
                Matrix transform = Matrix.CreateRotationY(batS.azimuth);

                Vector3 flyDirection = Vector3.TransformNormal(new Vector3(0, 0, -1), transform);

                batS.position -= flyDirection * batS.velocity * delta;
            }
        }
        #endregion

        #region Draw and DrawModel
        public void Draw(GraphicsDeviceManager graphics, GameTime gameTime)
        {
            foreach (BatObj batA in bats)
            {
                Matrix transform = Matrix.CreateRotationY(batA.azimuth) *
     Matrix.CreateTranslation(batA.position);

                DrawModel(graphics, bat, Matrix.CreateScale(batA.size) * transform);
            }
            //DrawModel(graphics, bat, Matrix.CreateScale(5) * Matrix.CreateTranslation(200, 200, 10) * Matrix.CreateRotationY(MathHelper.ToRadians(90)));
        }
        
        private void DrawModel(GraphicsDeviceManager graphics, Model model, Matrix world)
        {

            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);
            int count = model.Bones.Count;

            for (int i = 0; i < count; i++)
            {
                if (i == leftWing1)
                {
                    transforms[i] = Matrix.CreateRotationY(wingAngle);
                }
                else if (i == leftWing2)
                {
                    transforms[i] = Matrix.CreateRotationY(wingAngle);
                }
                else if (i == rightWing1)
                {
                    transforms[i] = Matrix.CreateRotationY(-wingAngle);
                }
                else if (i == rightWing2)
                {
                    transforms[i] = Matrix.CreateRotationY(-wingAngle);
                }
                else
                {
                    transforms[i] = Matrix.Identity;
                }
                ModelBone bone = model.Bones[i];
                if (bone.Parent == null)
                {
                    transforms[i] *= bone.Transform;
                }
                else
                {
                    transforms[i] *= bone.Transform * transforms[bone.Parent.Index];
                }
            }



            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = transforms[mesh.ParentBone.Index] * world;
                    effect.View = game.Camera.View;
                    effect.Projection = game.Camera.Projection;
                }
                mesh.Draw();
            }
        }
        #endregion

        private void startGame()
        {
            while (bats.Count < 22)
            {
                BatObj batObj = new BatObj();
                batObj.position = RandomVector(-100, 100);
                batObj.velocity = 50.0f;
                batObj.azimuth = -20.0f;
                batObj.elevation = (float)random.Next((int)Math.PI / 2);
                batObj.size = 5;
                batObj.health = 1;
                //if (batObj.position.Length() < 1000 || batObj.position.Y < 0)
                //  continue;
                bats.AddLast(batObj);
            }
        }
        public bool TestLaserForCollision(Vector3 position)
        {
            for (LinkedListNode<BatObj> batNode = bats.First; batNode != null; )
            {
                LinkedListNode<BatObj> nextNode = batNode.Next;
                BatObj batObj = batNode.Value;

                // Obtain a bounding sphere for the asteroid.  I can get away
                // with this here because I know the model has exactly one mesh
                // and exactly one bone.
                BoundingSphere bs = bat.Meshes[bat.Meshes.IndexOf(bat.Meshes["Body"])].BoundingSphere;
                bs = bs.Transform(bat.Bones[bat.Bones.IndexOf(bat.Bones["Body"])].Transform);

                // Move this to world coordinates.  Note how easy it is to 
                // transform a bounding sphere
                bs.Radius *= batObj.size;
                bs.Center += batObj.position;

                if ((position - bs.Center).LengthSquared() < bs.Radius * bs.Radius)
                {

                    batObj.health -= 1;
                    // We have a hit.  We'll delete this asteroid and return true
                    game.SoundBank.PlayCue("explosion2");
                    if (batObj.health == 0)
                    {     
                        bats.Remove(batNode);
                    }
                    return true;
                }

                batNode = nextNode;
            }

            return false;
        }
    }
}
